#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

template<class T>
using func_t = std::function<void(T&)>;

template<class T>
class Thread{
    public:
        Thread(const std::string &threadname, func_t<T> func, T &data) 
        :_tid(0), _threadname(threadname), _isrunning(false), _func(func), _data(data) {}
        
        static void *ThreadRoutine(void *args) {
            Thread *ts = static_cast<Thread *>(args);
            ts->_func(ts->_data);
            return nullptr;
        }

        bool Start() {
            int n = pthread_create(&_tid, nullptr, ThreadRoutine, this);
            if(n == 0) {
                _isrunning = true;
                return true;
            }
            return false;
        }

        bool Join() {
            if(!_isrunning) return true;

            int n = pthread_join(_tid, nullptr);
            if(n == 0) {
                _isrunning = false;
                return true;
            }
            return false;
        }

        std::string threadname() { return _threadname; }
        bool isrunning() { return _isrunning; }

        ~Thread() {}
    private:
        pthread_t _tid;
        std::string _threadname;
        bool _isrunning;
        func_t<T> _func;
        T _data;
};